home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’93
/
Mystery Science Mac
/
INIT sources
/
MSM.patches.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-01
|
9KB
|
359 lines
#include "MacHeaders7"
#include "Utils.h"
#include "MSM.h"
#include <Balloons.h>
#include <Processes.h>
traps Patches[myLast+1] = {
0xA93D,0,0, /* MenuSelect */
0xA96D,0,0, /* Draw1Control */
0xA912,0,0, /* InitWindows */
0x0000,0,0 /* Last */
};
/********************************************************************************/
/* it is necessary inside traps to have a convenient way of vectoring back
to the "old" trap routine. w/o multi-seg code resources, and if the
compiler were smart enough, this could be done with PC-relative code,
something like:
asm {
move.l Patches[myMove].oldAddress,-(a7)
rts
}
Note that this code preserves all registers. Unfortunately, this code
does not work in the world of Think C since globals are accessed relative
to a4. So instead, we call a routine named vector which performs like
LoadSeg - it converts the call to vector into a jsr.l or jmp.l to the
address in question. This makes future executions of this code faster,
too. (For those who are freaks about self-modifying code, it is possible
to modify vector in such a way that it acts as if there were a JMP or JSR,
without modifying any code. This would, however, be much harder to follow
when debugging through the patch code, and it would be slower, since every
time through, the address would have to be re-computed. As luck would
have it, the non-self-modifying code takes up less space, and while I was
debugging through it to make sure it worked, it turned up a bug in the
INIT I was writing where I was accidentally modifying the wrong entry in
the trap table. So it's included here for completeness sake and as yet
another way of making sure an INIT is squeaky clean.
The call to vector should be:
asm {
jsr vector
dc.w myMove
};
Sometimes you want to do a jsr rather than a jump. This is simple,
just invert the selector word:
asm {
jsr vector
dc.w ~myMove
}
Just to make things complete, we define 2 macros to invoke the vector:
*/
#define VectorJMP(myTrap) \
jsr vector \
dc.w myTrap
#define VectorJSR(myTrap) \
jsr vector \
dc.w ~myTrap
#define self_modifying_code 1
#if self_modifying_code
static void vector(short this_parameter_forces_a_link_instruction) {
asm {
_SetUpA4
movem.l a0/a1/d0/d1,-(a7) ; don’t disturb the registers!
move.w #0x4EF9,d1 ; 4EF9 = JMP.L
move.l 4(a6),a1 ; a1 is now the return address.
move.w (a1),d0 ; d0 is now the trap #.
bge.s @JMP
JSR: not.w d0
move.w #0x4EB9,d1 ; 4EB9 = JSR.L
JMP: subq #4,a1 ; a1 is now the point of original call.
move.l a1,4(a6) ; save it so we return there.
lea Patches,a0 ; get the address of Patches array in a0.
mulu.w #sizeof(traps),d0 ; d0 is now the offset into Patches for this particular trap.
move.w d1,(a1)+ ; d1 = JMP.L or JSR.L
move.l OFFSET(traps,oldAddress)(a0,d0),(a1)+
jsr FlushCache ; wipe the cache because we modified our own code.
movem.l (a7)+,a0/a1/d0/d1 ; save the registers.
_RestoreA4
}; /* and returning takes us back to the jump! */
}
#else
static void vector(void) {
asm {
link a6,#-4
move.l (a6),(a7) ; so we can easily leave extra space on the stack.
movem.l a0/d0,-(a7) ; don’t disturb the registers!
move.l 4(a6),a0 ; a1 is now the address of the inline param to vector.
move.w (a0)+,d0 ; d0 is now the trap #, and a0 is the real return address.
move.l a0,4(a6) ; save the new return address for the JSR case.
_SetUpA4
lea Patches,a0 ; get the address of Patches array in a0.
_RestoreA4 ; don’t need a4 anymore.
tst.w d0
bge.s @JMP ; negative d0 means we came from the JSR macro.
JSR: not.w d0 ; d0 is now the un-inverted trap #.
subq #4,a6 ; this puts 4 more bytes on the stack and saves the
; return address of the vector call on the stack. In
; the non-JSR case, the return address gets obliterated.
JMP: mulu.w #sizeof(traps),d0 ; d0 is now the offset into Patches for this particular trap.
move.l OFFSET(traps,oldAddress)(d0,a0),4(a6)
movem.l (a7)+,a0/d0
unlk a6
; rts ; this returns to the old trap address, which, either returns to the
; instruction after the VectorJSR macro or in the case of the
; VectorJMP macro, to wherever.
};
}
#endif
/********************************************************************************/
void FixA4(Handle h) {
asm {
move.l h,a0
GetHandleSize
tst.l d0
ble.s @LX
move.l (a0),a0
LP: subq #2,d0
beq @LX
cmpi.w #0x2F0C,(a0)+ ; 2F0C == 'move.l a4,-(a7)'
bne.s @LP
subq #2,d0
cmpi.w #0x49F9,(a0)+ ; 49F9 == 'lea 0x????,a4'
bne.s @LP
cmpi.l #'rga4',(a0) ; rga4 is what we want to replace
bne.s @LP
move.l a4,(a0)
bra.s @LP
LX:
}
}
extern char Launched : 0x910; /* if non-positive, we’re not running yet. */
CGrafPort *MSMPort;
long NeedBlack;
static short countDown = 8;
static void MakeTheHoleBlack(void) {
ProcessSerialNumber us, front;
GrafPtr oldPort;
// let's be really paranoid about when we do this.
// let's me sure the window manager exists, at least one program
// has been launched, there's a real menu bar, resources are set
// to be loaded, we have at least one menu in the menu bar, and
// there's at least 2K of stack space.
if (WWExist != 0 || Launched <= 0 || MBarHeight <= 0 || ResLoad == 0 ||
jbMenuList == 0 || *jbMenuList == 0 || (**jbMenuList).lastMenu == 0 ||
StackSpace() < 2048) return;
// and make sure the front process is us.
GetFrontProcess(&us);
GetCurrentProcess(&front);
if (us.highLongOfPSN != front.highLongOfPSN) return;
if (us.lowLongOfPSN != front.lowLongOfPSN) return;
if (countDown > 0) {
countDown--;
return;
}
if (TickCount() > NeedBlack) {
GetPort(&oldPort);
SetPort(MSMPort);
FillRgn(gMysterious, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF");
NeedBlack = TickCount() + 300;
SetPort(oldPort);
}
}
static long last_chk;
long last_non_dialog;
WindowPeek lastWP;
static short Microsoft, CopyOnce;
void pJGNEfilter(short what, EventRecord *ep) {
EventRecord er;
WindowPeek wp;
Rect r;
Point pt = ep->where, midpt;
long now = TickCount();
if (what == 0) {
er.what = nullEvent;
ep = &er;
}
switch(ep->what) {
case nullEvent:
wp = (WindowPeek) FrontWindow();
if (wp != NULL && wp->windowKind == 2 && GetWVariant(wp) == 1) {
CopyOnce = FALSE;
if (lastWP != wp) {
if (now - last_non_dialog > 600) {
r = (**wp->strucRgn).rgnBBox;
if (PtInRect(pt, &r)) {
QueueSound(7);
} else {
midpt.h = (r.left + r.right) / 2;
midpt.v = (r.top + r.bottom) / 2;
if (pt.h - pt.v > midpt.h - midpt.v) {
if (pt.h + pt.v > midpt.h + midpt.v) {
QueueSound(8);
} else {
QueueSound(10);
}
} else {
if (pt.h + pt.v > midpt.h + midpt.v) {
QueueSound(11);
} else {
QueueSound(9);
}
}
}
last_non_dialog = now;
}
} else {
last_non_dialog = now;
}
} else {
char title[256];
if (wp) GetWTitle(wp, title);
if (wp && title[0] == 4 && 'Copy' == *(long*)&title[1]) {
if (!CopyOnce) {
QueueSound(12);
CopyOnce = TRUE;
}
} else {
CopyOnce = FALSE;
last_non_dialog = now;
if (*(long *)0x911 == 'Micr') {
if (!Microsoft) {
Microsoft = TRUE;
QueueSound(3);
}
} else {
Microsoft = FALSE;
}
}
}
case updateEvt:
MakeTheHoleBlack();
break;
case mouseDown:
if (PtInRgn(pt, gMysterious)) {
QueueSound(6);
}
case mouseUp:
case keyDown:
last_non_dialog = now;
break;
}
}
pascal long pMenuSelect(Point pt) {
long result;
asm {
move.l 12(a6),-(a7)
move.l pt,-(a7)
VectorJSR(myMenuSelect)
move.l (a7)+,result
_SetUpA4
movem.l a0/a1/d0/d1/d2,-(a7)
}
if (MenuDisable == 0xBF960003) {
QueueSound(1); // PlayNamedSound("\pNot!", 0);
HMSetBalloons(FALSE);
} else if (result == 0x01050001) {
QueueSound(4);
} else if (result == 0x01050005) {
QueueSound(5);
} else {
}
asm {
movem.l (a7)+,a0/a1/d0/d1/d2
_RestoreA4
}
return result;
}
pascal void pDraw1Control(ControlHandle ch) {
uchar text[256];
GetCTitle(ch, text);
asm {
_SetUpA4
}
if (GetCtlValue(ch) == TRUE && jbRelString(text, "\pWarn before emptying") == 0) {
QueueSound(2); // PlayNamedSound("\pWimp!", 0);
}
asm {
_RestoreA4
unlk a6
VectorJMP(myDraw1Control);
}
}
extern long NeedBlack;
RgnHandle gMysterious;
static void PunchOut(void) {
GrafPtr oldPort;
Rect r, scrn;
THz z;
GetPort(&oldPort);
SetPort(WMgrCPort);
z = GetZone();
SetZone(SystemZone());
if (!gMysterious) {
gMysterious = NewRgn();
OpenRgn();
r.top = 50;
r.left = 50;
r.bottom = 150;
r.right = 150;
FrameOval(&r);
CloseRgn(gMysterious);
}
r = (**gMysterious).rgnBBox;
OffsetRgn(gMysterious, WMgrCPort->portRect.right - r.right, WMgrCPort->portRect.bottom - r.bottom);
PaintRgn(gMysterious);
DiffRgn(GrayRgn, gMysterious, GrayRgn);
SetZone(z);
SetPort(oldPort);
NeedBlack = TickCount();
}
pascal void pInitWindows(void) {
asm {
VectorJSR(myInitWindows);
movem.l d0/d1/d2/a0/a1/a4,-(a7)
link a6,#0
_SetUpA4
}
PunchOut();
asm {
unlk a6
movem.l (a7)+,d0/d1/d2/a0/a1/a4
}
}